module command.StartAppCommand;

import std.stdio;

import std.string;
import hunt.console.helper.QuestionHelper;
import hunt.console.input.Input;
import hunt.console.input.InputArgument;
import hunt.console.output.Output;
import hunt.console.question.Question;
import hunt.console.command.Command;
import std.file;
import hunt.util.Serialize;
import config.ConfigurationDefine;
import hunt.logging;
import msgtrans;
import client.MsgServerClient;
import client.LogicServerClient;
import message.Constants;
import core.thread;
import message.MsgDefine;
import client.ImClient;
import std.conv : to;
import google.protobuf;
import std.array;

import hunt.concurrency.Executors;
import hunt.concurrency.Scheduler;
import hunt.concurrency.ScheduledThreadPoolExecutor;
import core.time;
import hunt.util.Runnable;
import std.conv;
import hunt.serialization.JsonSerializer;
import client.RpcRequestsMap;

__gshared ScheduledThreadPoolExecutor executor;



__gshared MessageTransportServer gateServer;

class StartAppCommand : Command
{
  enum string configPath = "./config_test.json";

  private GateConfig _config;

  override protected void configure()
  {
    this
    .setName("start")
    .setDescription("Outputs a start.")
    .addArgument("config", InputArgument.OPTIONAL, "Name of the person to greet")
    ;
  }

  override protected int execute(Input input, Output output)
  {
    string name = input.getArgument("config");
    if (name is null) {
      name = "stranger";
    }

    parseConfig(name);
    initLog();
    startApp();

    return 0;
  }

  override protected void interact(Input input, Output output)
  {
    if (input.getArgument("config") is null) {
      //string name = (cast(QuestionHelper) (getHelper("question")))
      //.ask(input, output, new Question("What is your name?"));
       input.setArgument("config", configPath);
       output.writeln(format("Not specified config use default config %s", configPath));
    }
    else
    {
      output.writeln(format("start app with config : %s", input.getArgument("config")));
    }
  }

  private void parseConfig(string path)
  {
    string data = readText(path);
    _config = toOBJ!GateConfig(parseJSON(data));
    Config.getInstance().setConfig(_config);
  }

  private void initLog()
  {
    //LogConf conf;
    //conf.fileName = Config.getInstance().getConfig().log;
    //logLoadConf(conf);
  }

  void initSchedule()
  {
    executor = cast(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);//使用1个线程处理
    executor.scheduleAtFixedRate(
    new class Runnable {
      void run() {
        {
            RpcRequestsMap.getInstance().doWork();
        }
      }
    }
    , 1.seconds, 5.seconds);// 程序启动1秒后执行，每2秒执行一次
  }

  private void startApp()
  {
    initSchedule();

    foreach(LogicServerConf c ; _config.logicserver)
    {
      while(true)
      {
        MessageTransportClient client = new MessageTransportClient(logicClientName);
        client.channel(new TcpClientChannel(c.host, cast(ushort)c.port));
        client.connect();
        if(client.isConnected)
        {
          client.send(new MessageBuffer(MESSAGE.CMD_REGISTER_GATESERVER , []));
          LogicServerClient.getInstance().addForwardClient(c.id,client);
          break;
        }
        Thread.sleep(2.seconds);
      }

    }

    foreach(MsgServerConf c ; _config.msgserver)
    {
      while (true)
      {
        MessageTransportClient client = new MessageTransportClient(msgClientName);
        client.channel(new TcpClientChannel(c.host, cast(ushort)c.port));
        client.connect();
        if(client.isConnected)
        {
          client.send(new MessageBuffer(MESSAGE.CMD_REGISTER_GATESERVER , []));
          MsgServerClient.getInstance.addForwardClient(c.id,client);
          break;
        }
        Thread.sleep(2.seconds);
      }
    }

    gateServer = new MessageTransportServer(gateServerName);

    gateServer.addChannel(new TcpServerChannel(cast(ushort)_config.tcpport));

    gateServer.acceptor((TransportContext ctx) {
      infof("New connection: id=%d", ctx.id());
    });
    gateServer.closer((TransportContext ctx) {
        message.MsgDefine.User user =  cast(message.MsgDefine.User)ctx.session.getAttribute(SESSIONKEY.USER);
        AuthenticateREQ authorize = cast(AuthenticateREQ)ctx.session.getAttribute(SESSIONKEY.SRC);
        if (user !is null)
        {

          ImClient.getInstance().deleClient(ImClient.getInstance().idMixSrc(to!ulong(user.id), authorize.src));
          MessageTransportClient msgClient = MsgServerClient.getInstance.getForwardClient(user.id);
          UserStatus userStatus = new UserStatus;
          userStatus.userId = user.id;
          userStatus.src = authorize.src;
          msgClient.send(new MessageBuffer(MESSAGE.CMD_OFFLINE,userStatus.toProtobuf.array));
          logInfo("user :%s is close",user.id);
          ctx.session.setAttribute(SESSIONKEY.USER,null);
          ctx.session.setAttribute(SESSIONKEY.LOGINMSG,null);
        }
        else
        {
          logWarning("cast msg.User error");
        }
    });

    gateServer.start();
  }

}

